/*
 * @(#)ApproveInterruptRequest.java
 *
 * Copyright (c) 2005 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */

package com.dcivision.workflow.action;

import java.sql.Connection;
import java.util.List;

import org.quartz.JobDataMap;

import com.dcivision.framework.ApplicationException;
import com.dcivision.framework.DataSourceFactory;
import com.dcivision.framework.ErrorConstant;
import com.dcivision.framework.EventLogger;
import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.SystemFunctionConstant;
import com.dcivision.framework.Utility;
import com.dcivision.user.bean.UserRecord;
import com.dcivision.user.dao.UserRecordDAObject;
import com.dcivision.workflow.WorkflowErrorConstant;
import com.dcivision.workflow.bean.MtmWorkflowChildParentProgress;
import com.dcivision.workflow.bean.MtmWorkflowProgressSystemObject;
import com.dcivision.workflow.bean.MtmWorkflowProgressUserRecord;
import com.dcivision.workflow.bean.MtmWorkflowStepUserActor;
import com.dcivision.workflow.bean.MtmWorkflowTrackInterruptReq;
import com.dcivision.workflow.bean.WorkflowProgress;
import com.dcivision.workflow.bean.WorkflowStep;
import com.dcivision.workflow.core.WorkflowOperationManager;
import com.dcivision.workflow.core.WorkflowProgressManager;
import com.dcivision.workflow.core.WorkflowRetrievalManager;
import com.dcivision.workflow.dao.MtmWorkflowChildParentProgressDAObject;
import com.dcivision.workflow.dao.MtmWorkflowDynamicUserActorDAObject;
import com.dcivision.workflow.dao.MtmWorkflowProgressSystemObjectDAObject;
import com.dcivision.workflow.dao.MtmWorkflowProgressUserRecordDAObject;
import com.dcivision.workflow.dao.MtmWorkflowStepUserActorDAObject;
import com.dcivision.workflow.dao.MtmWorkflowTrackInterruptReqDAObject;
import com.dcivision.workflow.dao.WorkflowProgressDAObject;
import com.dcivision.workflow.dao.WorkflowStepDAObject;

/**
 * ApproveInterruptRequest.java
 *
 * Automatic task to approve interrupt request!
 *
 * @author           Dick Xie
 * @company          DCIVision Limited
 * @creation date    17/06/2005
 * @version          $Revision: 1.14.2.2 $
 */
public class ApproveInterruptRequest extends com.dcivision.workflow.core.WorkflowProcessor {

  /** Creates a new instance of ApproveInterruptRequest */
  public ApproveInterruptRequest() {
    //* define how many possible exit for the current, default to 1
    this.numOfRoutine = 1;
    //* if more than one routine defined, need to set the name of each
    // possible exit
    this.labelType = LABEL_TYPE_USER_DEFINE;
    this.labelString = new String[]{"workflow.label.step_status_G"};
  }

  public synchronized void execute(JobDataMap dataMap, WorkflowProgress currentProgress) throws ApplicationException {
    log.info("***** ApproveInterruptRequest workflow processor BEGIN *****");
    Connection conn = null;

    Integer trigerEventUserID = new Integer(0);
    String serverName = "127.0.0.1";
    String functionName = SystemFunctionConstant.WORKFLOW_TASK;
    String errorMessage = "";

    try {
      //* get the DB Connection
      SessionContainer sessionCon = this.getSessionContainer();

      /*************************************************************
       *  get Event Log Information Begin
       *************************************************************/
      if (!Utility.isEmpty(sessionCon.getUserRecordID())) {
        trigerEventUserID = sessionCon.getUserRecordID();
      }

      if (!Utility.isEmpty(sessionCon.getUserIPAddress())) {
        serverName = sessionCon.getUserIPAddress();
      }
      errorMessage =  "ApproveInterruptRequest.java -- Track ID: " + currentProgress.getTrackID()
                      + ", Workflow Progress ID : " + currentProgress.getID()
                      + ", Workflow Step ID: " + currentProgress.getWorkflowStepID()
                      + "<br> ";
      /*************************************************************
       *  get Event Log Information End
       *************************************************************/
      //for schedule job useing the processer connection.
      isLocalConnection = false;
      if (!Utility.isEmpty(this.getConnection())) {
        conn = this.getConnection();
      } else {
        isLocalConnection = true;
        conn = DataSourceFactory.getConnection();
      }

      //* get relevant information from
      //Integer userRecordID = null;
      //Integer trackID = currentProgress.getTrackID();

      //* get relevant information from
      log.info("current progress' workflow step id: "
          + currentProgress.getWorkflowStepID());

      //* do what you want below
      WorkflowStep currentStep = currentProgress.getWorkflowStepSource();
      UserRecordDAObject userRecordDAO = new UserRecordDAObject(sessionCon, conn);
      sessionCon.setUserRecord((UserRecord) userRecordDAO.getObjectByID(currentProgress.getCreatorID()));
      this.approveInterruptRquest(currentStep, currentProgress, sessionCon, conn);

      //* after the execution, set the desired appropriate out number
      this.returnRoutineIndex = 0; //* should be between 0 and
      // numOfRoutine-1
      //* if need to auto-Execute the following step, set the below
      // variable to true (default false)
      this.bAutoExecuteNextStep = false;
      //* if no need to create the child workflow progress, set the below
      // variable to false (default true)
      this.bCreateNextWorkflowProgress = false;

      if (isLocalConnection) {
        conn.commit();
      }
    } catch (ApplicationException appEx) {
      log.error("Application exception:\n" + appEx);
      /***********************************
       *  Record the Event Log.
       ***********************************/
      EventLogger.logEventMessage(trigerEventUserID, serverName, errorMessage, appEx.getMsgCode(), WorkflowErrorConstant.LOG_AUTO_TASK_ERROR_CODE, functionName, appEx.toString());

      throw appEx; //* prop
    } catch (Exception e) {
      log.error("Error during processing this automatic task.", e);
      /***********************************
       *  Record the Event Log.
       ***********************************/
      EventLogger.logEventMessage(trigerEventUserID, serverName, errorMessage, ErrorConstant.COMMON_FATAL_ERROR, WorkflowErrorConstant.LOG_AUTO_TASK_ERROR_CODE, functionName, e.toString());

      throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR); //*

    } finally {
      if (isLocalConnection) {
        try { conn.close(); } catch (Exception ignore) { } finally { conn = null; }
      }
    }

    log.info("***** ApproveInterruptRequest workflow processor END   *****");
  }

  private void approveInterruptRquest(WorkflowStep currentStep, WorkflowProgress curProgress, SessionContainer sessionContainer, Connection dbConn) throws ApplicationException {
    WorkflowProgressManager progressManager = new WorkflowProgressManager(sessionContainer, dbConn);
    WorkflowRetrievalManager retrievalManager = new WorkflowRetrievalManager(sessionContainer, dbConn);
    WorkflowOperationManager operationManager = new WorkflowOperationManager(sessionContainer, dbConn);
    MtmWorkflowChildParentProgressDAObject childWorkflowParentProgressDAO = new MtmWorkflowChildParentProgressDAObject(sessionContainer, dbConn);
    WorkflowProgressDAObject progressDAO = new WorkflowProgressDAObject(sessionContainer, dbConn);
    MtmWorkflowStepUserActorDAObject stepUserActorDAO = new MtmWorkflowStepUserActorDAObject(sessionContainer, dbConn);
    MtmWorkflowProgressSystemObjectDAObject mtmWfProgSysObjDAO = new MtmWorkflowProgressSystemObjectDAObject(sessionContainer, dbConn);
    MtmWorkflowTrackInterruptReqDAObject  workflowTrackInterruptReqDAO = new MtmWorkflowTrackInterruptReqDAObject(sessionContainer, dbConn);
    MtmWorkflowProgressUserRecordDAObject progressUserRecordDAO = new MtmWorkflowProgressUserRecordDAObject(sessionContainer, dbConn);
    WorkflowStepDAObject workflowStepDAO = new WorkflowStepDAObject(sessionContainer, dbConn);


    List parentWorkflowList = childWorkflowParentProgressDAO.getListByTrackID(curProgress.getTrackID());
    for (int i = 0; i < parentWorkflowList.size(); i++) {
      MtmWorkflowChildParentProgress tmp = (MtmWorkflowChildParentProgress) parentWorkflowList.get(i);
      WorkflowProgress parentProgress = (WorkflowProgress) progressDAO.getObjectByID(tmp.getParentWorkflowProgressID());
      MtmWorkflowProgressSystemObject relatedObj = (MtmWorkflowProgressSystemObject) mtmWfProgSysObjDAO.getObjectByTrackIDObjectID(curProgress.getTrackID(), null);
      java.util.Map dataMap = (java.util.Map) relatedObj.getParameterObject();
      Object workflowObj = dataMap.get("WORKFLOW_OBJECT");
       //  If it is a workflow interruption subworkflow
      if (workflowObj instanceof MtmWorkflowTrackInterruptReq) {
        MtmWorkflowTrackInterruptReq interruptReq = (MtmWorkflowTrackInterruptReq) workflowObj;
        WorkflowProgress preProgress = new WorkflowProgress();
        if (workflowObj instanceof com.dcivision.workflow.bean.MtmWorkflowTrackInterruptReq && relatedObj != null && relatedObj.getParameterObject() != null) {
          if (MtmWorkflowTrackInterruptReq.INTERRUPT_TYPE_ROLLBACK.equals(interruptReq.getInterruptType().toString())) {
            List progressList = retrievalManager.getLockedProgressList(parentProgress.getTrackID(), interruptReq.getTargetStepID());
            for (int k = 0; k < progressList.size(); k++) {
              WorkflowProgress currentProgress = (WorkflowProgress) progressList.get(k);
              currentProgress.setStatus(WorkflowProgress.STATUS_ROLLBACK);
              currentProgress = (WorkflowProgress) progressDAO.updateObject(currentProgress);
              // Update currentProgress related User record;
              List progressUserRecordList = progressUserRecordDAO.getListByWorkflowProgressID(currentProgress.getID());
              for (int h = 0; !Utility.isEmpty(progressUserRecordList) && h < progressUserRecordList.size(); h++) {
                MtmWorkflowProgressUserRecord progressUserRecord = (MtmWorkflowProgressUserRecord) progressUserRecordList.get(h);
                progressUserRecord.setWorkflowAction(WorkflowProgress.STATUS_ROLLBACK);
                progressUserRecord = (MtmWorkflowProgressUserRecord) progressUserRecordDAO.updateObject(progressUserRecord);
              }
             // Update current progress is Calendar record;
              progressManager.editCalendarByProgressID(currentProgress.getID(), null);
            }
            preProgress.setStatus(WorkflowProgress.STATUS_ROLLBACK);
          } else if (MtmWorkflowTrackInterruptReq.INTERRUPT_TYPE_REVOKE.equals(interruptReq.getInterruptType().toString())) {
            parentProgress.setStatus(WorkflowProgress.STATUS_REVOKE);
            preProgress.setStatus(WorkflowProgress.STATUS_REVOKE);

            // Update user record from "LOCK" status into "REVOKE".
            List lockStatusUserRecordList = progressUserRecordDAO.getListByWorkflowProgressID(parentProgress.getID(), WorkflowProgress.STATUS_LOCK);

            for (int h = 0; h < lockStatusUserRecordList.size(); h++) {
              MtmWorkflowProgressUserRecord lockStatusUserRecord = (MtmWorkflowProgressUserRecord) lockStatusUserRecordList.get(h);
              lockStatusUserRecord.setWorkflowAction(WorkflowProgress.STATUS_REVOKE);
              progressUserRecordDAO.updateObject(lockStatusUserRecord);
            }

          } else if (MtmWorkflowTrackInterruptReq.INTERRUPT_TYPE_SKIP.equals(interruptReq.getInterruptType().toString())) {
            parentProgress.setStatus(WorkflowProgress.STATUS_SKIP);
            preProgress.setStatus(WorkflowProgress.STATUS_SKIP);
          } else if (MtmWorkflowTrackInterruptReq.INTERRUPT_TYPE_STOP.equals(interruptReq.getInterruptType().toString())) {
            List progressList = retrievalManager.getLockedProgressList(parentProgress.getTrackID(), null);
            for (int k = 0; k < progressList.size(); k++) {
              WorkflowProgress currentProgress = (WorkflowProgress) progressList.get(k);
              currentProgress.setStatus(WorkflowProgress.STATUS_CANCEL);
              currentProgress = (WorkflowProgress) progressDAO.updateObject(currentProgress);
              // Update currentProgress related User record;
              List progressUserRecordList = progressUserRecordDAO.getListByWorkflowProgressID(currentProgress.getID(), WorkflowProgress.STATUS_LOCK);
              for (int h = 0; !Utility.isEmpty(progressUserRecordList) && h < progressUserRecordList.size(); h++) {
                MtmWorkflowProgressUserRecord progressUserRecord = (MtmWorkflowProgressUserRecord) progressUserRecordList.get(h);
                progressUserRecord.setWorkflowAction(WorkflowProgress.STATUS_CANCEL);
                progressUserRecord = (MtmWorkflowProgressUserRecord) progressUserRecordDAO.updateObject(progressUserRecord);
              }
//                Update current progress is Calendar record;
              progressManager.editCalendarByProgressID(currentProgress.getID(), null);
            }
            preProgress.setStatus(WorkflowProgress.STATUS_CANCEL);
          }
          if (!MtmWorkflowTrackInterruptReq.INTERRUPT_TYPE_ROLLBACK.equals(interruptReq.getInterruptType().toString()) && !MtmWorkflowTrackInterruptReq.INTERRUPT_TYPE_STOP.equals(interruptReq.getInterruptType().toString())) {
            parentProgress = (WorkflowProgress) progressDAO.updateObject(parentProgress);
//               Update current progress is Calendar record;
            progressManager.editCalendarByProgressID(parentProgress.getID(), null);
          }
          WorkflowProgress newProgress = new WorkflowProgress();
          if (MtmWorkflowTrackInterruptReq.INTERRUPT_TYPE_ROLLBACK.equals(interruptReq.getInterruptType().toString()) || MtmWorkflowTrackInterruptReq.INTERRUPT_TYPE_REVOKE.equals(interruptReq.getInterruptType().toString())) {
            List newProgressList = progressDAO.getListByStepIDAndTrackID(interruptReq.getTargetStepID(), interruptReq.getWorkflowTrackID());

            if (!Utility.isEmpty(newProgressList)) {
              newProgress = (WorkflowProgress) newProgressList.get(0);
            }
            WorkflowStep workflowStep = (WorkflowStep) workflowStepDAO.getObjectByID(newProgress.getWorkflowStepID());
            newProgress.setProgressPriority(workflowStep.getPriority());
            if (GlobalConstant.TRUE.equals(newProgress.getCompleteFlag())) {
              newProgress.setStatus(WorkflowProgress.STATUS_GENERAL_ACCOMPLISHMENT);
            } else {
              newProgress.setStatus(WorkflowProgress.STATUS_PENDING);
            }
            List progressList = progressDAO.getListByTrackID(parentProgress.getTrackID());
            int seqNoCount = progressList.size() + 1;
            newProgress.setSeqNo(new Integer(seqNoCount));
            newProgress.setID(null);
            newProgress = (WorkflowProgress) progressDAO.insertObject(newProgress);
            // if new progress is assign user owner is assign ,get old user action taker to new
            this.insertUserRecordForAssignUser(newProgress, dbConn, sessionContainer);
            // create notification job for this step
            boolean actorTypeIsAssgin = false;
            List userActorList = stepUserActorDAO.getListByWorkflowStepID(newProgress.getWorkflowStepID());
            if (!Utility.isEmpty(userActorList)) {
              for (int j = 0; j < userActorList.size(); j++) {
                MtmWorkflowStepUserActor stepUserActor = (MtmWorkflowStepUserActor) userActorList.get(j);
                if (MtmWorkflowStepUserActor.ACTOR_TYPE_RUNTIME_ASSIGN.equals(stepUserActor.getActorType())) {
                  actorTypeIsAssgin = true;
                }
              }
            }
            if (!actorTypeIsAssgin) {
              progressManager.createNotificationWhenTaskArrived(newProgress.getID());
            }
           //                    set dynamic assign priority.
            progressManager.createScheduleForProgressPriority(newProgress.getID(), sessionContainer, dbConn);
            progressManager.insertMtmWorkflowProgressMtmWorkflowProgress(parentProgress, newProgress, interruptReq.getInterruptStatus());
          } else if (MtmWorkflowTrackInterruptReq.INTERRUPT_TYPE_SKIP.equals(interruptReq.getInterruptType().toString())) {
            WorkflowStep newStep = (WorkflowStep) workflowStepDAO.getObjectByID(interruptReq.getTargetStepID());
            progressManager.createNextWorkflowProgressesForSkipWorkflow(parentProgress, newStep);
          } else if (MtmWorkflowTrackInterruptReq.INTERRUPT_TYPE_STOP.equals(interruptReq.getInterruptType().toString())) {
            WorkflowStep parentStep = (WorkflowStep) workflowStepDAO.getObjectByID(parentProgress.getWorkflowStepID());
            operationManager.stopWorkflowTrack(parentProgress, parentStep);
          }
        }
        if (MtmWorkflowTrackInterruptReq.INTERRUPT_TYPE_ROLLBACK.equals(interruptReq.getInterruptType().toString())) {
          List progressUserRecordList = progressUserRecordDAO.getListByWorkflowProgressID(parentProgress.getID());
          for (int h = 0; !Utility.isEmpty(progressUserRecordList) && h < progressUserRecordList.size(); h++) {
            MtmWorkflowProgressUserRecord progressUserRecord = (MtmWorkflowProgressUserRecord) progressUserRecordList.get(h);
            progressUserRecord.setWorkflowAction(WorkflowProgress.STATUS_ROLLBACK);
            progressUserRecord = (MtmWorkflowProgressUserRecord) progressUserRecordDAO.updateObject(progressUserRecord);
          }
        }

        interruptReq.setInterruptStatus(preProgress.getStatus());
        interruptReq = (MtmWorkflowTrackInterruptReq) workflowTrackInterruptReqDAO.updateObject(interruptReq);

        // Update progress related object record.
        dataMap.put("WORKFLOW_OBJECT", interruptReq);
        relatedObj.setParameterObject(dataMap);
        mtmWfProgSysObjDAO.updateObject(relatedObj);
      } // If it is a normal subworkflow
    }
  }

  private void insertUserRecordForAssignUser(WorkflowProgress workflowProgress, Connection conn, SessionContainer sessionCon)throws ApplicationException {

    MtmWorkflowStepUserActorDAObject mtmWorkflowStepUserActorDAObject = new MtmWorkflowStepUserActorDAObject(sessionCon, conn);
    MtmWorkflowProgressUserRecordDAObject progressUserRecordDAO = new MtmWorkflowProgressUserRecordDAObject(sessionCon, conn);
    MtmWorkflowDynamicUserActorDAObject dynamicUserActorDAO = new MtmWorkflowDynamicUserActorDAObject(sessionCon, conn);
    WorkflowProgressDAObject workflowProgessDAO = new WorkflowProgressDAObject(sessionCon, conn);
    try {
      MtmWorkflowStepUserActor mtmWorkflowStepUserActor = mtmWorkflowStepUserActorDAObject.getWorkflowStepUserActorByWorkflowStepID(workflowProgress.getWorkflowStepID());
      if (!Utility.isEmpty(mtmWorkflowStepUserActor)) {
        List workflowProgressList = workflowProgessDAO.getListByStepIDAndTrackID(workflowProgress.getWorkflowStepID(), workflowProgress.getTrackID());
        if (!Utility.isEmpty(workflowProgressList)) {
          WorkflowProgress currentProgress = (WorkflowProgress) workflowProgressList.get(0);
          List mtmUserRecordList = progressUserRecordDAO.getListByWorkflowProgressID(currentProgress.getID());
          for (int h = 0; !Utility.isEmpty(mtmUserRecordList) && h < mtmUserRecordList.size(); h++) {
            MtmWorkflowProgressUserRecord  mtmUserRecord = (MtmWorkflowProgressUserRecord) mtmUserRecordList.get(h);
            mtmUserRecord.setID(null);
            mtmUserRecord.setWorkflowProgressID(workflowProgress.getID());
            if (GlobalConstant.TRUE.equals(workflowProgress.getCompleteFlag())) {
              mtmUserRecord.setWorkflowAction(WorkflowProgress.STATUS_GENERAL_ACCOMPLISHMENT);
            } else {
              mtmUserRecord.setWorkflowAction(WorkflowProgress.STATUS_PENDING);
            }
            mtmUserRecord = (MtmWorkflowProgressUserRecord) progressUserRecordDAO.insertObject(mtmUserRecord);
          }
          dynamicUserActorDAO.copyRecordByWorkflowProgressID(currentProgress.getID(), workflowProgress.getID());
        }
      }
    } catch (ApplicationException ex) {
      log.error(ex, ex);
    }
  }


}
